﻿#include "canvas.h"

ShapeManager::ShapeManager(Canvas* parent)
	: QObject(parent),
	detect_shape(nullptr),
	linked_shape(nullptr),
	create_shape(nullptr),
	finish_press(false),
	linked_creat(false),
	select_state(SelectOperate::Select),
	position(GirdPosition::Missing)
{
	canvas = parent;
	createPaint(PainterType::PaintShape);
}


void ShapeManager::beforePaint()
{
	paint_stream.clear();
}

void ShapeManager::createPaint(PainterType paint, const QPoint& start_point, const QPoint& final_point)
{
	canvas->paint_manager[paint]->setStart(start_point);
	canvas->paint_manager[paint]->setFinal(final_point);
	if (paint_stream.contains(paint))
		return;
	paint_stream.push_back(paint);
}

void ShapeManager::createPaint(PainterType paint)
{
	if (paint_stream.contains(paint))
		return;
	paint_stream.push_back(paint);
}

void ShapeManager::finishPaint()
{
	canvas->update();
}

void ShapeManager::recordBegin(const QPoint& point)
{
	cursor_begin = point;
	cursor_moved = point;
	//分为三种情况：点击位置位于选中框内，点击位置位于某个图形内，点击位置未命中任何目标；第三种情况需要清除选中图形
	//if (select_shape.size() >= 1)
	//{
	//	QPoint start_point = canvas->paint_manager[PainterType::PaintBorder]->getStart();
	//	QPoint final_point = canvas->paint_manager[PainterType::PaintBorder]->getFinal();
	//	QRect rect(start_point.x(), start_point.y(), final_point.x() - start_point.x(), final_point.y() - start_point.y());
	//	if (rect.contains(point))
	//	{
	//		for (auto shape : select_shape)
	//		{
	//			if (shape->nodesDetect(point))
	//			{
	//				select_state = SelectOperate::Connect;
	//				linked_shape = shape;
	//				linked_shape->setNodeIndex(point);
	//				createPaint(PainterType::PaintConnect, QPoint(shape->getMinX(), shape->getMinY()), QPoint(shape->getMinX(), shape->getMinY()));
	//				finishPaint();
	//				break;
	//			}
	//			select_state = SelectOperate::Move;
	//		}
	//	}
	//	else
	//	{
	//		select_state = SelectOperate::Select;
	//		select_shape.clear();
	//	}
	//}
	//if (select_state == SelectOperate::Select)
	//{
	//	for (auto shape : entire_shape)
	//	{
	//		if (shape->nodesDetect(point))
	//		{
	//			select_state = SelectOperate::Connect;
	//			linked_shape = shape;
	//			linked_shape->setNodeIndex(point);
	//			createPaint(PainterType::PaintConnect, QPoint(shape->getMinX(), shape->getMinY()), QPoint(shape->getMinX(), shape->getMinY()));
	//			finishPaint();
	//			break;
	//		}
	//		else if (shape->clickDetect(point))
	//		{
	//			select_shape.push_back(shape);
	//			select_state = SelectOperate::Move;
	//			createPaint(PainterType::PaintBorder, QPoint(shape->getMinX(), shape->getMinY()), QPoint(shape->getMaxX(), shape->getMaxY()));
	//			finishPaint();
	//			break;
	//		}
	//	}
	//}
	////这一部分只检测覆盖，不设置操作的类型
	//if (paint_stream.contains(PainterType::PaintBorder))
	//{
	//	BorderPainter* painter = dynamic_cast<BorderPainter*>(canvas->paint_manager[PainterType::PaintBorder]);
	//	position = painter->BorderDetect(point);
	//	switch (position)
	//	{
	//	case GirdPosition::Missing:
	//		canvas->setCursor(Qt::ArrowCursor);
	//		break;
	//	case GirdPosition::LeftTop:
	//	case GirdPosition::RightEnd:
	//		canvas->setCursor(Qt::SizeFDiagCursor);
	//		select_state = SelectOperate::Stretch;
	//		break;
	//	case GirdPosition::LeftMid:
	//	case GirdPosition::RightMid:
	//		canvas->setCursor(Qt::SizeHorCursor);
	//		select_state = SelectOperate::Stretch;
	//		break;
	//	case GirdPosition::LeftEnd:
	//	case GirdPosition::RightTop:
	//		canvas->setCursor(Qt::SizeBDiagCursor);
	//		select_state = SelectOperate::Stretch;
	//		break;
	//	case GirdPosition::MainTop:
	//	case GirdPosition::MainEnd:
	//		canvas->setCursor(Qt::SizeVerCursor);
	//		select_state = SelectOperate::Stretch;
	//		break;
	//	default:
	//		break;
	//	}
	//}
	//finish_press = true;


	if (paint_stream.contains(PainterType::PaintBorder))
	{
		//先检查缩放
		BorderPainter* painter = dynamic_cast<BorderPainter*>(canvas->paint_manager[PainterType::PaintBorder]);
		position = painter->BorderDetect(point);
		switch (position)
		{
		case GirdPosition::Missing:
			canvas->setCursor(Qt::ArrowCursor);
			break;
		case GirdPosition::LeftTop:
		case GirdPosition::RightEnd:
			canvas->setCursor(Qt::SizeFDiagCursor);
			select_state = SelectOperate::Stretch;
			break;
		case GirdPosition::LeftMid:
		case GirdPosition::RightMid:
			canvas->setCursor(Qt::SizeHorCursor);
			select_state = SelectOperate::Stretch;
			break;
		case GirdPosition::LeftEnd:
		case GirdPosition::RightTop:
			canvas->setCursor(Qt::SizeBDiagCursor);
			select_state = SelectOperate::Stretch;
			break;
		case GirdPosition::MainTop:
		case GirdPosition::MainEnd:
			canvas->setCursor(Qt::SizeVerCursor);
			select_state = SelectOperate::Stretch;
			break;
		default:
			break;
		}
		//再检查移动和链接
		if (select_state != SelectOperate::Stretch)
		{
			QPoint start_point = canvas->paint_manager[PainterType::PaintBorder]->getStart();
			QPoint final_point = canvas->paint_manager[PainterType::PaintBorder]->getFinal();
			QRect rect(start_point.x(), start_point.y(), final_point.x() - start_point.x(), final_point.y() - start_point.y());
			if (rect.contains(point))
			{
				for (auto shape : select_shape)
				{
					if (shape->nodesDetect(point))
					{
						select_state = SelectOperate::Connect;
						linked_shape = shape;
						linked_shape->setNodeIndex(point);
						createPaint(PainterType::PaintConnect, QPoint(shape->getMinX(), shape->getMinY()), QPoint(shape->getMinX(), shape->getMinY()));
						finishPaint();
						break;
					}
					select_state = SelectOperate::Move;
				}
			}
			else
			{
				select_state = SelectOperate::Select;
				select_shape.clear();
			}
		}
	}
	if (select_state == SelectOperate::Select)
	{
		for (auto shape : entire_shape)
		{
			if (shape->nodesDetect(point))
			{
				select_state = SelectOperate::Connect;
				linked_shape = shape;
				linked_shape->setNodeIndex(point);
				createPaint(PainterType::PaintConnect, QPoint(shape->getMinX(), shape->getMinY()), QPoint(shape->getMinX(), shape->getMinY()));
				finishPaint();
				break;
			}
			else if (shape->clickDetect(point))
			{
				select_shape.push_back(shape);
				select_state = SelectOperate::Move;
				createPaint(PainterType::PaintBorder, QPoint(shape->getMinX(), shape->getMinY()), QPoint(shape->getMaxX(), shape->getMaxY()));
				finishPaint();
				break;
			}
		}
	}
	finish_press = true;
}

void ShapeManager::recordMoved(const QPoint& point)
{
	int dx = point.x() - cursor_moved.x();
	int dy = point.y() - cursor_moved.y();
	cursor_moved = point;
	//分为两种情况：按下鼠标移动和未按下鼠标移动，后者检测会比较消耗性能
	detect_shape = nullptr;
	for (auto shape : entire_shape)
	{
		if (shape->clickDetect(cursor_moved) || shape->nodesDetect(cursor_moved))
		{
			detect_shape = shape;
			break;
		}
	}
	if (paint_stream.contains(PainterType::PaintBorder) && position == GirdPosition::Missing)
	{
		BorderPainter* painter = dynamic_cast<BorderPainter*>(canvas->paint_manager[PainterType::PaintBorder]);
		switch (painter->BorderDetect(point))
		{
		case GirdPosition::Missing:
			canvas->setCursor(Qt::ArrowCursor);
			break;
		case GirdPosition::LeftTop:
		case GirdPosition::RightEnd:
			canvas->setCursor(Qt::SizeFDiagCursor);
			break;
		case GirdPosition::LeftMid:
		case GirdPosition::RightMid:
			canvas->setCursor(Qt::SizeHorCursor);
			break;
		case GirdPosition::LeftEnd:
		case GirdPosition::RightTop:
			canvas->setCursor(Qt::SizeBDiagCursor);
			break;
		case GirdPosition::MainTop:
		case GirdPosition::MainEnd:
			canvas->setCursor(Qt::SizeVerCursor);
			break;
		default:
			break;
		}
	}
	//按下鼠标移动
	if (finish_press)
	{
		beforePaint();
		//绘制选中区域
		if (select_state == SelectOperate::Select)
		{
			createPaint(PainterType::PaintSelect, cursor_begin, cursor_moved);
		}
		//绘制图形
		createPaint(PainterType::PaintShape);
		//绘制连线
		createPaint(PainterType::PaintConnect);
		if (select_state == SelectOperate::Move)
		{
			QPoint start_point = canvas->paint_manager[PainterType::PaintBorder]->getStart();
			QPoint final_point = canvas->paint_manager[PainterType::PaintBorder]->getFinal();
			//移动边框
			createPaint(PainterType::PaintBorder, QPoint(start_point.x() + dx, start_point.y() + dy), QPoint(final_point.x() + dx, final_point.y() + dy));
			//移动图形
			for (auto shape : select_shape)
			{
				//必须保证图形要留一部分在画布内，否则移出画布范围后点击不到会无法操作，默认的话要保证终点距离左上角dx>10，dy>10，起点距离右下角dx>10，dy>10
				//if (shape->getMaxX() + dx < 10 || shape->getMaxY() + dy < 10)
					//return;
				//if (shape->getMinX() + dx > canvas->width() - 10 || shape->getMinY() + dy > canvas->height() - 10)
					//return;
				shape->setStartPoint(QPoint(shape->getMinX() + dx, shape->getMinY() + dy));
			}
		}
		if (select_state == SelectOperate::Connect)
		{
			if (!linked_creat)
			{
				ShapeLink* link = new ShapeLink(this, linked_shape, linked_shape->getNode());
				linked_group.push_back(link);
				linked_creat = true;
			}
			linked_group.at(linked_group.size() - 1)->setFinalPoint(point);
			//移动连线
			createPaint(PainterType::PaintConnect);
		}
		if (select_state == SelectOperate::Stretch)
		{
			QPoint start_point = canvas->paint_manager[PainterType::PaintBorder]->getStart();
			QPoint final_point = canvas->paint_manager[PainterType::PaintBorder]->getFinal();
			int s_dx = 0, s_dy = 0, f_dx = 0, f_dy = 0;
			switch (position)
			{
			case GirdPosition::LeftTop:
				start_point.setX(start_point.x() + dx);
				s_dx = dx;
				start_point.setY(start_point.y() + dy);
				f_dy = dy;
				break;
			case GirdPosition::LeftMid:
				start_point.setX(start_point.x() + dx);
				s_dx = dx;
				break;
			case GirdPosition::LeftEnd:
				start_point.setX(start_point.x() + dx);
				s_dx = dx;
				final_point.setY(final_point.y() + dy);
				f_dy = dy;
				break;
			case GirdPosition::MainTop:
				start_point.setY(start_point.y() + dy);
				s_dy = dy;
				break;
			case GirdPosition::MainEnd:
				final_point.setY(final_point.y() + dy);
				f_dy = dy;
				break;
			case GirdPosition::RightTop:
				final_point.setX(final_point.x() + dx);
				f_dx = dx;
				start_point.setY(start_point.y() + dy);
				s_dy = dy;
				break;
			case GirdPosition::RightMid:
				final_point.setX(final_point.x() + dx);
				f_dx = dx;
				break;
			case GirdPosition::RightEnd:
				final_point.setX(final_point.x() + dx);
				f_dx = dx;
				final_point.setY(final_point.y() + dy);
				f_dy = dy;
				break;
			default:
				break;
			}
			for (auto shape : select_shape)
			{
				shape->setStartPoint(QPoint(shape->getMinX() + s_dx, shape->getMinY() + s_dy));
				shape->setShapeWidth(shape->getMaxX() - shape->getMinX() + f_dx - s_dx);
				shape->setShapeHeight(shape->getMaxY() - shape->getMinY() + f_dy - s_dy);
			}
			createPaint(PainterType::PaintBorder, start_point, final_point);
		}
		finishPaint();
	}
	else
	{
		createPaint(PainterType::PaintShape);
		finishPaint();
	}

}

void ShapeManager::recordFinal(const QPoint& point)
{
	cursor_final = point;
	beforePaint();
	//绘制图形
	createPaint(PainterType::PaintShape);
	//绘制连线
	createPaint(PainterType::PaintConnect);
	//绘制选中边框
	int max_x = -1, max_y = -1, min_x = -1, min_y = -1;
	if (select_state == SelectOperate::Select)
	{
		for (auto shape : entire_shape)
		{
			//如果被范围选中则参与计算边框大小的计算
			if (shape->scopeDetect(cursor_begin, cursor_final.x() - cursor_begin.x(), cursor_final.y() - cursor_begin.y()))
			{
				min_x = (min_x == -1) ? shape->getMinX() : std::min(min_x, shape->getMinX());
				min_y = (min_y == -1) ? shape->getMinY() : std::min(min_y, shape->getMinY());
				max_x = (max_x == -1) ? shape->getMaxX() : std::max(max_x, shape->getMaxX());
				max_y = (max_y == -1) ? shape->getMaxY() : std::max(max_y, shape->getMaxY());
				select_shape.push_back(shape);
			}
		}
		if (select_shape.size() > 0)
			createPaint(PainterType::PaintBorder, QPoint(min_x, min_y), QPoint(max_x, max_y));
	}
	if (select_state == SelectOperate::Move)
	{
		createPaint(PainterType::PaintBorder);
	}
	if (select_state == SelectOperate::Connect)
	{
		for (auto shape : entire_shape)
		{
			if (shape->nodesDetect(point))
			{
				shape->setNodeIndex(point);
				linked_group.at(linked_group.size() - 1)->setFinalShape(shape);
				linked_group.at(linked_group.size() - 1)->setFinalIndex(shape->getNode());
			}
		}
	}
	if (select_state == SelectOperate::Stretch)
	{
		createPaint(PainterType::PaintBorder);
	}
	finishPaint();
	finish_press = false;
	linked_creat = false;
	select_state = SelectOperate::Select;
	canvas->setCursor(Qt::ArrowCursor);
	position = GirdPosition::Missing;
}

void ShapeManager::recordShape(Shape* shape, CreateMode mode, const QPoint& point)
{
	if (mode == CreateMode::Save)
	{
		if (create_shape != nullptr)
		{
			entire_shape.push_back(create_shape);
			create_shape = nullptr;
		}
	}
	if (mode == CreateMode::Move)
	{
		//传递的是全局坐标，需要转换为本地坐标
		QPoint local_point = canvas->mapFromGlobal(point);
		if (create_shape != nullptr)
		{
			create_shape->setStartPoint(QPoint(local_point.x() - create_shape->getWidth() / 2, local_point.y() - create_shape->getHeight() / 2));
		}
	}
	if (mode == CreateMode::Edit)
	{
		if (shape == nullptr)
		{
			if (create_shape != nullptr)
			{
				delete create_shape;
				create_shape = nullptr;
			}
		}
		else
		{
			create_shape = shape;
		}
	}
}

Shape* ShapeManager::detectShape() const
{
	return detect_shape;
}

Shape* ShapeManager::createShape() const
{
	return create_shape;
}

const QList<Shape*>& ShapeManager::selectShape() const
{
	return select_shape;
}

const QList<Shape*>& ShapeManager::entireShape() const
{
	return entire_shape;
}

const QList<ShapeLink*>& ShapeManager::linkedGroup() const
{
	return linked_group;
}



Canvas::Canvas(QWidget* parent)
	: QWidget(parent)
{
	shape_manager = new ShapeManager(this);
	//初始化绘制器
	paint_manager[PainterType::PaintBorder] = new BorderPainter(this);
	paint_manager[PainterType::PaintShape] = new ShapePainter(this, shape_manager);
	paint_manager[PainterType::PaintSelect] = new SelectPainter(this);
	paint_manager[PainterType::PaintConnect] = new ConnectPainter(this, shape_manager);

	//初始化菜单栏
	popup_manager = new PopMenu(this);
	popup_manager->addAction("shape", "复用");
	popup_manager->addAction("shape", "删除");
	popup_manager->addAction("layer", "置于顶层", ":/icons/layer_top.ico");
	popup_manager->addAction("layer", "置于底层", ":/icons/layer_end.ico");
	popup_manager->addAction("layer", "上移一层", ":/icons/layer_up.ico");
	popup_manager->addAction("layer", "下移一层", ":/icons/layer_down.ico");
	setMouseTracking(true);
}

ShapeManager* Canvas::getShapeManager() const
{
	return shape_manager;
}

void Canvas::mousePressEvent(QMouseEvent* event)
{
	shape_manager->recordBegin(event->pos());
	if (event->button() == Qt::RightButton)
	{
		popup_manager->setShowPoint(event->globalPos().x(), event->globalPos().y());
		popup_manager->show();
		popup_manager->activateWindow();
		popup_manager->setFocus();
	}
}

void Canvas::mouseMoveEvent(QMouseEvent* event)
{
	shape_manager->recordMoved(event->pos());
}

void Canvas::mouseReleaseEvent(QMouseEvent* event)
{
	shape_manager->recordFinal(event->pos());
}

void Canvas::paintEvent(QPaintEvent* event)
{
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);
	for (auto type : shape_manager->paint_stream)
	{
		paint_manager[type]->paint(painter);
	}
}

